package main

import (
	"config-client-v1/test/plc-s7-test/pkg"
	"config-client-v1/utils/tools"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/robinson/gos7"
	"time"
)

var client gos7.Client
var jsonFile *string
var list []*pkg.FrameItemParam

func main() {
	tcpDevice := flag.String("tcp_device", "192.168.1.131", "IP:端口")
	rack := flag.Int("rack", 1, "机架")
	slot := flag.Int("slot", 1, "插槽")
	jsonFile = flag.String("json_file", "plcs7-1.json", "帧格式json文件")
	flag.Parse()
	err := loadingFrameItem()
	if err != nil {
		fmt.Printf("加载帧格式失败 %v\n", err.Error())
		return
	}
	fmt.Printf("tcpDevice=%s,rack=%d,slot=%d\n", *tcpDevice, *rack, *slot)
	handler := gos7.NewTCPClientHandler(*tcpDevice, *rack, *slot)
	handler.Timeout = 200 * time.Second
	handler.IdleTimeout = 200 * time.Second
	err = handler.Connect()
	if err != nil {
		fmt.Println("Connect ERROR", err)
		return
	}
	defer handler.Close()
	client = gos7.NewClient(handler) // init client
	address := 1                     // DB号
	start := 0x0100                  // 起始地址
	counter := 0
	for {
		buffer, err := createFrameRawData()
		if err != nil {
			fmt.Printf("生成数据包失败 %s\n", err)
			return
		}
		size := len(buffer)
		err = client.AGWriteDB(address, start, size, buffer)
		if err != nil {
			fmt.Printf("AGWriteDB ERROR [%d] %v\n", counter, err)
			return
		}
		fmt.Printf("[%s] DB.%d.%d.%d #%v\n", tools.GetNow(), address, start, size, buffer)
		counter++
		time.Sleep(1 * time.Second)
	}
}

func loadingFrameItem() (err error) {
	str, err := tools.ReadFileContent(*jsonFile)
	if err != nil {
		err = errors.New(fmt.Sprintf("读取帧格式文件失败 %s\n", err))
		return
	}
	list = make([]*pkg.FrameItemParam, 0)
	err = json.Unmarshal([]byte(str), &list)
	if err != nil {
		return
	}
	if len(list) == 0 {
		err = errors.New("帧格式为空, 请重新编辑")
		return
	}
	return
}

func createFrameRawData() (data []byte, err error) {
	data = make([]byte, 0)
	uniqueKeyBoolMap := make(map[string]bool)
	for i := 0; i < len(list); i++ {
		val := list[i]
		if list[i].Start > list[i].End {
			err = errors.New("开始字节不可大于结束字节")
			return
		}
		if i > 0 && len(list) > 1 {
			if !uniqueKeyBoolMap[fmt.Sprintf("%d", val.Start)] && list[i].Start != (list[i-1].End+1) {
				err = errors.New(fmt.Sprintf("[%s] 和前面字段不连续 %d~%d", val.FieldName, val.Start, val.End))
				return
			}
		}
		l := val.End - val.Start + 1
		switch val.SpecType {
		case "int8":
			fallthrough
		case "uint8":
			if l != 1 {
				err = errors.New(fmt.Sprintf("%s 占用字节异常", val.FieldName))
				return
			}
			data = append(data, uint8(tools.GetRandAreaNumber(0, 255)))
		case "int16":
			fallthrough
		case "uint16":
			if l != 2 {
				err = errors.New(fmt.Sprintf("%s 占用字节异常", val.FieldName))
				return
			}
			v := uint16(tools.GetRandAreaNumber(0, 65535))
			b := tools.Uint16ToBytes(v, "big")
			data = append(data, b[:]...)
		case "int32":
			fallthrough
		case "uint32":
			if l != 4 {
				err = errors.New(fmt.Sprintf("%s 占用字节异常", val.FieldName))
				return
			}
			v := uint32(tools.GetRandAreaNumber(3200000, 3300000))
			b := tools.Uint32ToBytes(v, "big")
			data = append(data, b[:]...)
		case "float32":
			if l != 4 {
				err = errors.New(fmt.Sprintf("%s 占用字节异常", val.FieldName))
				return
			}
			b := tools.Float32ToBytes4(float32(tools.GetRandAreaNumber(8000, 10000))/float32(100.0), "big")
			data = append(data, b[:]...)
		case "bool":
			if l != 1 {
				err = errors.New(fmt.Sprintf("%s 占用字节异常", val.FieldName))
				return
			}
			data = append(data, uint8(tools.GetRandAreaNumber(0, 1)))
		case "string":
			if l == 4 {
				str := GenRandomString()
				data = append(data, []byte(str)...)
			} else {
				data = append(data, []byte(tools.GetRandomString(l))...)
			}
		default:
			err = errors.New(fmt.Sprintf("%s spec_type 参数无效", val.FieldName))
			return
		}
	}
	return
}

func GenRandomString() string {
	pool := []string{"rain", "snow", "nice", "bird", "fish", "book", "wind", "moon", "baby", "back", "bank", "base", "best", "cake", "city", "demo", "desk", "exit", "fire", "film"}
	index := tools.GetRandAreaNumber(0, len(pool)-1)
	return pool[index]
}
